package ongd.negocio.gestion;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import ongd.negocio.sesion.ControladorSesion;
import ongd.servicios.persistencia.ControladorPersistencia;
import ongd.servicios.persistencia.exceptions.IllegalOrphanException;
import ongd.servicios.persistencia.exceptions.NonexistentEntityException;
import ongd.servicios.persistencia.exceptions.PreexistingEntityException;

/**
 * Clase que realizará las operaciones necesarias para gestionar los socios.
 *
 * @author <a href="mailto:egi0002@alu.ubu.es">Elena García Iglesias</a>
 * @author <a href="mailto:cms0021@alu.ubu.es">Cristina Martínez Sanz</a>
 * @version 1.0 20120124
 */
public class ControladorSocio extends ControladorPersona {

    /**
     * Constructor de la clase.
     * @param contSesion session en la que estamos
     * @param contP controlador persistencia
     */
    public ControladorSocio(ControladorPersistencia contP, ControladorSesion contSesion) {
        super(contP, contSesion);
    }

    /**
     * Método que crea un socio.
     * @param persona Socio a crear
     * @param listaF Lista de fraccionados
     * @return cadena que indica si se ha realizado la operación
     * @throws PreexistingEntityException
     * @throws Exception 
     */
    public String crearSocio(Persona persona, List<Fraccionado> listaF) throws PreexistingEntityException, Exception {
        if (buscarPersona(persona.getDni()) == null) {
            if (persona.esSocio() && persona.getDni() != null && persona.getNombre() != null && persona.getApellidos() != null
                    && persona.getCantidad() != null && persona.getDomiciliacion() != null && !listaF.isEmpty()) {
                if (!persona.getDomiciliacion() || (persona.getDomiciliacion() && persona.getNCuenta() != null)) {
                    //Inicio la transacción con la base de datos
                    getContP().iniciarTransaccion();
                    //Establezco la fecha de registro al diá actual
                    persona.setFechaRegistro(new Date());
                    getContP().crearEntidad(persona);
                    //crearemos las cuotas correspondientes.
                    crearFraccionados(persona, listaF);
                    crearCuotas(persona, persona.getCantidad());
                    getContP().terminarTransaccion();
                    return "Correcto";
                }
            }
        } else {
            return "Repetido";
        }
        return "Incorrecto";
    }

    /**
     * Método que edita un socio, en función de los booleanos pasados por 
     * parámetro.
     * @param socio socio a editar
     * @param listaF lista de fracciones que serán las nuevas fracciones del 
     * socio
     * @return true si la operación se ha realizado correctamente
     * @throws IllegalOrphanException
     * @throws NonexistentEntityException
     * @throws Exception 
     */
    public boolean editarSocio(Persona socio, List<Fraccionado> listaF) throws IllegalOrphanException, NonexistentEntityException, Exception {
        if (socio.esSocio()) {
            if (socio.getDni() != null && socio.getNombre() != null && socio.getApellidos() != null && socio.getCantidad() != null
                    && socio.getDomiciliacion() != null) {
                if (!socio.getDomiciliacion() || (socio.getDomiciliacion() && socio.getNCuenta() != null)) {
                    //Inicio la transacción con la base de datos
                    getContP().iniciarTransaccion();
                    getContP().editarEntidad(socio);
                    if (listaF == null) {
                        //Edito el socio, considerando que la lista del mismo no ha cambiado.
                        editarPagoFraccionado(socio.getFraccionadoList());
                        editarCuota(socio);
                    } else {
                        //si la listaF no está vacia, implica que hemos cambiado el pago fraccionado
                        //borraré el pago fraccionado que tenia antes.
                        borrarPagoFraccionado(socio.getFraccionadoList());
                        //borraré las cuotas pendientes que tenia el socio.
                        double cantidadAbonada = borrarCuotasPendientes(socio.getCuotaList());
                        getContP().terminarTransaccion();
                        getContP().iniciarTransaccion();
                        //crearé el nuevo pago fraccionado a partir de la lista.
                        crearFraccionados(socio, listaF);
                        //Calculo la cantidad que se debe de abonar
                        double cantidad = socio.getCantidad() - cantidadAbonada;
                        //Si la cantidad es mayor que 0 creo las nuevas cuotas
                        if (cantidad > 0) {
                            //obtengo las nuevas cuotas necesarias
                            crearCuotas(socio, cantidad);
                        }
                    }
                    //Termino la transacción con la base de datos
                    getContP().terminarTransaccion();
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Método que borra un socio de la base de datos.
     * @param persona que va a ser borrado
     * @return true si la operación se ha realizado correctamente
     * @throws IllegalOrphanException
     * @throws NonexistentEntityException 
     * @throws Exception
     */
    @Override
    public boolean borrarPersona(Persona persona) throws IllegalOrphanException, NonexistentEntityException, Exception {
        boolean borrado = false;
        //Si la persona existe
        if (getContP().obtenerEntidad(Persona.class, persona.getDni()) != null) {
            if (persona.esSocio()) {
                //Miraré si ese socio tiene cuotas abonadadas, ya que si las tiene no podré borrarle
                boolean abonadas = false;
                for (Cuota c : persona.getCuotaList()) {
                    if (c.esAbonada() && abonadas == false) {
                        abonadas = true;
                    }
                }
                //Si no tiene cuotas abonadas, borro el socio
                if (!abonadas) {
                    //Inicio la transacción
                    getContP().iniciarTransaccion();
                    borrarPagoFraccionado(persona.getFraccionadoList());
                    borrarCuotas(persona.getCuotaList());
                    getContP().destroyEntidad(Persona.class, persona.getDni());
                    //Finalizo la transacción
                    getContP().terminarTransaccion();
                    borrado = true;
                }
            }
        }
        return borrado;
    }

    /**
     * Método que da de baja un socio.
     * @param persona Socio a dar de baja
     * @return true que indica si la operación se ha realizado correctamente
     * @throws IllegalOrphanException
     * @throws NonexistentEntityException
     * @throws Exception 
     */
    @Override
    public boolean darBajaPersona(Persona persona) throws IllegalOrphanException, NonexistentEntityException, Exception {
        if (persona.esSocio()) {
            //Si la persona existe
            if (getContP().obtenerEntidad(Persona.class, persona.getDni()) != null) {
                if (persona.getFechaBaja() == null) {
                    //Pongo la fecha de baja del socio a la fecha actual
                    persona.setFechaBaja(new Date());
                    //Inicio la transacción
                    getContP().iniciarTransaccion();
                    getContP().editarEntidad(persona);
                    cancelarCuotasPendientes(persona.getCuotaList());
                    //Finalizo la transacción
                    getContP().terminarTransaccion();
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Método que da de alta una persona en la base de datos.
     * @param persona Persona que vamos a dar de alta
     * @return true o false en función de si la operación se ha realizado
     * correctamente
     * @throws IllegalOrphanException
     * @throws NonexistentEntityException
     * @throws Exception 
     */
    public boolean darAltaPersona(Persona persona) throws IllegalOrphanException, NonexistentEntityException, Exception {
        //Si el socio existe
        if (getContP().obtenerEntidad(Persona.class, persona.getDni()) != null) {
            if (persona.getFechaBaja() != null) {
                Calendar fechaActual = Calendar.getInstance();
                int anno = fechaActual.get(Calendar.YEAR);
                //Obtengo las cuotas que tiene ese socio
                List<Cuota> cuotasAnuales = obtenerCuotasAnuales(persona, anno);
                //Si la lista devuelta es vacia crearé las cuotas correspondientes
                //Iniciamos las transacción
                getContP().iniciarTransaccion();
                if (cuotasAnuales.isEmpty()) {
                    crearCuotas(persona, persona.getCantidad());
                } else {
                    //Miraré a ver si existe alguna cuota abonada de las cuotas anuales
                    double cantidadAbonada = 0;
                    for (Cuota c : cuotasAnuales) {
                        if (c.esAbonada()) {
                            cantidadAbonada += c.getCantidad();
                        }
                    }
                    //Obtengo la cantidad pendiente a pagar
                    double cantidadPendiente = persona.getCantidad() - cantidadAbonada;
                    if (cantidadPendiente > 0) {
                        //Obtengo las cuotas que hay canceladas a partir de la fecha actual
                        List<Cuota> cuotasCanceladas = obtenerCuotasCanceladas(cuotasAnuales);
                        //Establezco esas cuotas a pendientes y cambio la cantidad por lo que corresponda
                        establecerCuotasPendientes(cuotasCanceladas, cantidadPendiente);
                    }
                }
                persona.setFechaBaja(null);
                getContP().editarEntidad(persona);
                //Finalizo la transacción
                getContP().terminarTransaccion();
                return true;
            }
        }
        return false;
    }
}